import fs from 'fs';
import glob from 'glob';
import path from 'path';
import crypto from 'crypto';

export { tools };

declare let RES_CFG_PATH: string;

namespace tools {
	export type GENERAL_CFG_TYPE = {
		cfg_path: string;
		cfg_file: string;
		img_cfg_file: string;
		img_hash_file: string;
		res_cfg_name: string;
	}

	export type EGRET_CFG_TYPE = {
		path: string;
		localization?: LOCAL_CFG_TYPE;
		resource_gen?: RES_GEN_TYPE;
		auto_eui_str?: AUTO_EUI_TYPE;
		assets_clean?: ASSETS_CLEAN_TYPE;
	}

	export type LOCAL_CFG_TYPE = {
		config_path: string;
	}

	export type RES_GEN_TYPE = {
		exclude_cfg_file: string[];
	}

	export type AUTO_EUI_TYPE = {
		eui_str_name: string;
		eui_str_key: string;
		eui_str_path: string;
	}

	export type ASSETS_CLEAN_TYPE = {
		delete_file_exc: string[];
	}

	export type WIN_CFG_TYPE = {
		resourcePlugin: { configs: { configPath: string, relativePath: string }[] },
		theme: string;
	}

	export type IMG_ASSEMBLY_CFG = {
		path?: string; //总配置里面会用到，子文件不需要
		cfg_file?: string; //同样总配置里面会用到
		output_dir: string;
		output_cfg: PNG_OPTIONS;
	}

	export type PNG_OPTIONS = {
		compressionLevel: number;
		adaptiveFiltering: false;
		quality: number;
		palette: boolean;
		dither: number;
		colors: number;
	}

	export type GENRATOR_CFG_TYPE = {
		name: string;
		res_path: string;
		include: string[];
		exclude: string[];
		rename?: { [url: string]: string[] };
		group_cfg: string;
		outputdir: string;
	}

	export type GROUP_CFG_TYPE = {
		include: string[];
		exclude: string[];
	};

	export type RES_FILE_TYPE = {
		resources: RES_TYPE[],
		groups: GROUP_TYPE[]
	}

	export type RES_TYPE = {
		name: string;
		type: string;
		url: string;
		picUrl?: string; //中间态，类型为font和sheet的配置需要把png的路径临时存一份做检查用，实际写入数据的时候记得删掉
		subkeys?: string; //图集要用到
	}

	export type GROUP_TYPE = {
		name: string;
		keys: string;
	};

	export type GROUP_MID_TYPE = {
		name: string;
		keys: string[];
	}

	export type IMG_SHEET_TYPE = {
		output_dir: string;
		output_file: string;
		cfg_dir: string; //当前配置文件所在绝对路径，ResGenrator.AssetsCheck会生成，可以不填 //哈希的时候用一下
		include: string[];
		output_cfg?: PNG_OPTIONS;
	}

	export type TRANS_CFG_TYPE = {
		appId: string;
		ver: number;
		from_language: number;
		to_languages: string[];
		include_folder: string[];
		cfg_file_set: { file: string, to_file: string }[];
		tables: {
			[fileName: string]: { key: string, fields: (string | number)[] }
		}
	}

	export function GenricCfg(): GENERAL_CFG_TYPE {
		return genericCfg || (genericCfg = JSON.parse(fs.readFileSync(`${GENERIC_CFG_PATH}/general_cfg.json`, {
			encoding: 'utf-8'
		})));
	}

	export function QueryEgretProperties(projPath: string): EGRET_CFG_TYPE | undefined {
		let comCfg = GenricCfg();
		let properties = fs.readFileSync(`${projPath}/egretProperties.json`, { encoding: 'utf-8' });
		if (!properties) {
			return;
		}
		try {
			let prop = JSON.parse(properties);
			return prop[comCfg.res_cfg_name];
		} catch (e) {
			console.warn(e);
			return;
		}
	}

	export function QueryWingProperties(projPath: string): WIN_CFG_TYPE {
		try {
			let properties = fs.readFileSync(`${projPath}/wingProperties.json`, { encoding: 'utf-8' });
			return JSON.parse(properties);
		} catch (e) {
			console.warn(e);
			return { resourcePlugin: { configs: [] }, theme: "" };
		}
	}

	export function SaveWingProperties(projPath: string, cfg: WIN_CFG_TYPE): void {
		let path = `${projPath}/wingProperties.json`;
		fs.existsSync(path) && fs.writeFileSync(path, JSON.stringify(cfg, null, '\t'), { encoding: 'utf-8' });
	}

	export function TypeCfg(): { [type: string]: string } {
		return typeCfg || (typeCfg = JSON.parse(fs.readFileSync(`${GENERIC_CFG_PATH}/type_cfg.json`, {
			encoding: 'utf-8'
		})));
	}

	/**
	 * 生成一个文件夹
	 * @param path - 绝对路径
	 * @param clear - 如果已经存在是否清除文件夹下面的所有内容
	 */
	export function CreateFolder(path: string, clear: boolean = false) {
		if (fs.existsSync(path)) {
			if (clear) {
				fs.rmdirSync(path, { recursive: true });
			} else {
				return;
			}
		}
		fs.mkdirSync(path, { recursive: true });
	}

	export function Time(): string {
		let date = new Date();
		return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}:${date.getMilliseconds()}`
	}

	export async function GlobFiles(includes: string[], excludes: string[], extPath?: string, option?: glob.IOptions): Promise<string[]> {
		return new Promise<string[]>((resolve) => {
			function checkData(includes: string[], excludes: string[]) {

				for (let exclude of excludes) {
					let index = includes.indexOf(exclude);
					if (index >= 0) {
						includes.splice(index, 1);
					}
				}
				resolve(includes);
			}

			Promise.all([GlobFile(includes, extPath, option), GlobFile(excludes, extPath, option)]).then(results => {
				checkData(results[0], results[1]);
			});
		});
	}

	export function Hash(data: string | Buffer): string {
		return crypto.createHash('sha256').update(data).digest('hex');
	}

	export function HashNum(data: string | Buffer): number {
		return parseInt(Hash(data), 16);
	}

	export async function GlobFile(patterns: string[], extPath?: string, option?: glob.IOptions) {
		if (!patterns || patterns.length < 1) {
			return [];
		}
		return new Promise<string[]>(resolve => {
			let num = patterns.length;
			let result: string[] = [];
			for (let pattern of patterns) {
				glob(`${!!extPath ? extPath + '/' : ''}${pattern}`, option || {}, (err, matches) => {
					if (!err) {
						result.push(...matches);
					}
					(--num == 0) && resolve(result);
				});
			}
		});
	}

	export function unescape(str: string, invert?: boolean): string {
		let index = 0;
		let key: string;
		let val: string;
		let checkKey: string;
		while (index < str.length) {
			//最近的一个转义符
			let currentIndex = -1;
			for (let curKey in escapeCharacterDic) {
				key = invert ? curKey : escapeCharacterDic[curKey];
				const tmpIndex = str.indexOf(key, index);
				if (currentIndex == -1 && tmpIndex != -1) {
					currentIndex = tmpIndex;
					checkKey = curKey;
				}
				if (currentIndex != -1 && tmpIndex != -1) {
					if (tmpIndex < currentIndex) {
						currentIndex = tmpIndex;
						checkKey = curKey;
					}
				}
			}
			if (currentIndex == -1) {
				break;
			} else {
				key = invert ? checkKey! : escapeCharacterDic[checkKey!];
				val = invert ? escapeCharacterDic[checkKey!] : checkKey!;
				const str1: string = str.slice(0, currentIndex);
				const str2: string = val;
				const str3: string = str.slice(currentIndex + key.length);
				str = str1 + str2 + str3;
				index = currentIndex + val.length;
			}
		}
		return str;
	}

	let genericCfg: GENERAL_CFG_TYPE;
	let typeCfg: { [type: string]: string };

	const escapeCharacterDic: { [from: string]: string } = {
		'\\a': '\a',
		'\\b': '\b',
		'\\f': '\f',
		'\\n': '\n',
		'\\r': '\r',
		'\\t': '\t',
		'\\v': '\v',
		'\\\\': '\\',
		'\\\'': '\'',
		'\\\"': '\"',
		'\\0': '\0',
		'\\ddd': '\ddd'
	}

	const GENERIC_CFG_PATH = path.join(__dirname, RES_CFG_PATH);//'./resources/genrator_cfg`;
	export const TMP_IMG_PATH = `${GENERIC_CFG_PATH}/img_cfg_tmp.json`;
	export const DEF_RES_PATH = 'resource';
}